// @ts-ignore
import Node from './Node.ts'
// @ts-ignore
import { ILinkList } from './Interface.ts'

class LinkList<T> implements ILinkList<T> {
  private _head: Node<T> | null = null
  private _tail: Node<T> | null = null
  private _size = 0

  private readonly POSITION_ERROR = 'position is not valid'
  private readonly NODE_NOT_EXIST = 'this node is not exist'

  /**
   *
   * @param position 从0开始
   */
  private getNodeByPosition(position: number) {
    if (!this.isPositionValid(position)) return null
    // 尾节点快速返回 无需遍历
    if (position === this._size - 1) return this._tail

    let point = this._head
    while (position) {
      point = point!.next
      position--
    }

    return point
  }

  private isPositionValid(position: number) {
    return position >= 0 && position < this._size
  }

  append(element: T) {
    const node = new Node<T>(element)
    if (!this._head) {
      this._head = node
    } else {
      this._tail!.next = node
    }

    this._tail = node
    this._size++

    return this
  }

  insert(position: number, element: T) {
    if (position < 0 || position > this._size) throw new Error(this.POSITION_ERROR)
    // 在尾节点插入
    if (position === this._size) return this.append(element)

    const newNode = new Node<T>(element)
    // 头节点之前插入
    if (position === 0) {
      newNode.next = this._head
      this._head = newNode
    } else {
      // 中间插入
      const pNode = this.getNodeByPosition(position - 1)
      newNode.next = pNode!.next
      pNode!.next = newNode
    }

    this._size++
    return this
  }

  removeAt(position: number) {
    if (!this.isPositionValid(position)) throw new Error(this.POSITION_ERROR)
    let removeValue: T
    // 删除头
    if (position === 0) {
      removeValue = this._head!.value
      this._head = this._head!.next
      // 防止遗留旧尾节点
      if (this._size === 1) this._tail = null
    } else if (position === this._size - 1) {
      // 删除尾
      removeValue = this._tail!.value
      this._tail = this.getNodeByPosition(position - 1)
      this._tail!.next = null
    } else {
      // 找到要删除的前一个节点
      const preNode = this.getNodeByPosition(position - 1)
      const removeNode = preNode?.next
      removeValue = removeNode!.value
      preNode!.next = removeNode!.next
    }

    this._size--
    return removeValue
  }

  remove(element: T) {
    const position = this.indexOf(element)
    if (position === -1) throw new Error(this.NODE_NOT_EXIST)
    return this.removeAt(position)
  }

  clear() {
    this._head = null
    this._tail = null
    this._size = 0
  }

  update(position: number, element: T) {
    if (!this.isPositionValid(position)) throw new Error(this.POSITION_ERROR)

    const node = this.getNodeByPosition(position)
    node!.value = element
    return this
  }

  get(position: number) {
    return this.getNodeByPosition(position)?.value ?? null
  }

  indexOf(element: T) {
    if (!this._size) return -1

    let index = 0
    let point = this._head

    while (point) {
      if (point!.value === element) return index
      point = point!.next
      index++
    }

    return -1
  }

  isEmpty() {
    return this._size === 0
  }

  get size() {
    return this._size
  }

  get head() {
    return this._head
  }

  get tail() {
    return this._tail
  }

  toString() {
    if (!this._head) return 'EMPTY'

    let result = `HEAD`
    let node: Node<T> | null = this._head
    while (node) {
      result += `->${node.value}`
      node = node.next
    }
    return result + '->NULL'
  }
}

export default LinkList
